import * as THREE from 'three';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
import BasicScene from './scene/BasicScene';
import { throttle } from 'lodash';

export interface MainSceneOptions {
  canvas?: HTMLCanvasElement | null;
  width?: number;
  height?: number;
}

export default class MainScene {
  /**
   * Main canvas element
   */
  readonly canvas: HTMLCanvasElement;
  readonly SceneMap: Record<string, BasicScene>;
  readonly camera: THREE.Camera;
  readonly scene: THREE.Scene;
  readonly renderer: THREE.WebGLRenderer;
  private mouseV: number;
  private mouseK: number;
  private hadListenMouseMove: boolean;
  private ObjLoader: OBJLoader;
  private MtlLoader: MTLLoader;
  constructor({ canvas, width = window.innerWidth, height = window.innerHeight }: MainSceneOptions) {
    this.canvas = canvas ?? document.createElement('canvas');
    this.ObjLoader = new OBJLoader();
    this.MtlLoader = new MTLLoader();
    this.SceneMap = {};

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
    camera.position.z = 50;
    scene.background = new THREE.Color(0xeeeeee);

    const light = new THREE.AmbientLight(0xffffff);
    scene.add(light);

    const axesHelper = new THREE.AxesHelper(150);
    scene.add(axesHelper);
    // scene.fog = new THREE.Fog(0xeeeeee, 1, 80);

    // add item to scene

    const renderer = new THREE.WebGLRenderer({ canvas: this.canvas });
    this.canvas.width = width;
    this.canvas.height = height;
    renderer.setSize(width, height);

    this.scene = scene;
    this.camera = camera;
    this.renderer = renderer;
    this.mouseV = 0;
    this.mouseK = 0;
    this.hadListenMouseMove = false;
    // this.ListenMouseMove();
    const animate = (time: number) => {
      requestAnimationFrame(animate);
      this._updateRotation();
      for (const i in this.SceneMap) {
        this.SceneMap[i].animate(time);
      }
      renderer.render(scene, camera);
    };
    animate(0);
  }

  AddScene(scene: BasicScene) {
    this.SceneMap[scene.id] = scene;
  }

  ChangeScene(id: string) {
    for (const i in this.SceneMap) {
      this.SceneMap[i].onSceneChange(id);
    }
  }

  /**
   * 开始监听鼠标移动的钩子
   *
   * 一般在入场动画结束后调用
   */
  ListenMouseMove() {
    if (this.hadListenMouseMove !== true) {
      window.addEventListener('mousemove', this.rotateScene);
      this.hadListenMouseMove = true;
    }
  }

  /**
   * 取消监听鼠标移动的钩子
   */
  StopListenMouseMove() {
    if (this.hadListenMouseMove === true) {
      window.removeEventListener('mousemove', this.rotateScene);
      this.hadListenMouseMove = false;
    }
  }

  /**
   * 场景归中到水平位置
   *
   * @param immediately 立即归中
   */
  AlignCameraCenter(immediately = false) {
    if (immediately && this.scene != null) {
      this.scene.rotation.x = 0;
      this.scene.rotation.y = 0;
      this.mouseV = 0;
      this.mouseK = 0;
      return;
    }
    const e = new MouseEvent('click', {
      clientX: this.canvas.width / 2,
      clientY: this.canvas.height / 2,
    });
    this.rotateScene(e);
  }

  // 监听鼠标移动旋转场景
  private readonly rotateScene = throttle((e: MouseEvent) => {
    console.log(1);
    this.mouseV = 3e-4 * (e.clientX - this.canvas.width / 2);
    this.mouseK = 1e-4 * (e.clientY - this.canvas.height / 2);
  }, 100);

  // 更新场景旋转
  private _updateRotation() {
    if (this.scene != null) {
      this.scene.rotation.y += (this.mouseV - this.scene.rotation.y) / 300;
      this.scene.rotation.x += (this.mouseK - this.scene.rotation.x) / 300;
    }
  }
}
